/****************************************************************************
** @brief concrete state subcalsses
****************************************************************************/

#include "sys/time.h"

#include "chargingStatus.h"
#include "stopingStatus.h"
#include "finishStatus.h"

#include "../hciMain.h"
#include "../cardMain.h"
#include "../oiovMain.h"
#include "../oiovCallback.h"
#include "../controllerMain.h"
#include "../card/abstractCard.h"
#include "../recordMain.h"

#include "../../controller/controller_can.h"
#include "../../iov/feestrategy-lib/inc/app_fee_strategy.h"

#include <QDebug>
#define CHARGINGSTATE_DEBUG

#define STOP_TIMEOUT   (100)

Status *ChargingStatus::instance_ = nullptr;

ChargingStatus::ChargingStatus() : Status()
{
    state_ = Status::kCharging;
}

ChargingStatus::~ChargingStatus()
{

}

Status *ChargingStatus::instance()
{
    if (nullptr == instance_) {
        instance_ = new ChargingStatus();
    }
    return instance_;
}

void ChargingStatus::Process(Gun *g)
{
    static int fi_calculate_stable = 0, order_stable = 0;

    time_t _time;
    struct tm *_tm;

    time(&_time);
    _tm = localtime(&_time); //current time

    size_t i;
    QString str;
    QVariantHash vhash;
    signed int elect = 0;
    unsigned char no = g->gun_number();

    if ((CONGUNNOA != no) && (CONGUNNOB != no)) {
        return;
    }

    no = no - CONGUNNOA;

#if defined(CHARGINGSTATE_DEBUG)
    static int count = 0;
    if (++count >= 5 * 1000 / 100) {
        count = 0;
        qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging state... ( time:" << get_fi_total_time((enum fee_number)no) << "elect:" << get_fi_total_elect((enum fee_number)no)
                 << "e-fee:" << get_fi_total_elec_fee((enum fee_number)no) << "s-fee:" << get_fi_total_service_fee((enum fee_number)no) << ")";
    }
#endif

    switch (ControllerParserMain::con_telecommand[no].work_state) {
    case WAIT_STATE:
        ChangeState(g, FinishStatus::instance()); //切换到充电完成未拔枪

#if defined(CHARGINGSTATE_DEBUG)
        qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging -> finish";
#endif

        //充电结束，不要上报充电中的属性数据了
        OiovReqMain::ClearChargingProperty(no);

        //设备状态 -> 充电结束未拔枪
        OiovCallback::ops_property_charge_data[no].status = OiovCallback::OPS_CHARGINGPILE_STATE_IDLE;
        //向平台发送设备状态事件
        OiovReqMain::SetDeviceStatusEvent(no);

        //data - 填充交易记录
        switch (ControllerParserMain::con_charg_stop_result[no].result_code) {
        case 0x02:
            switch (ControllerParserMain::con_charg_stop_result[no].fault_code_one) {
            case 0x01:
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_72; //急停故障
                break;
            case 0x04:
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_71; //绝缘模块故障
                break;
            default:
                break;
            }
            break;
        case 0x05:
            if (0x01 == ControllerParserMain::con_charg_stop_result[no].con_bms_fault_code.bms_fault_code_out_link_overtemp) {
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_74; //输出连接器过温故障
            }
            break;
        default:
            break;
        }
        //上报交易记录
        if (OiovCallback::OPS_TRANSACTION_TYPE_APP == OiovCallback::ops_event_bill[no].transaction_type || OiovCallback::OPS_TRANSACTION_TYPE_ONCARD == OiovCallback::ops_event_bill[no].transaction_type) {
            OiovReqMain::SetStopChargeEvent(no);
        }
        break;
    case CONF_STATE:
        break;
    case CHARGING_STATE:
        if (++fi_calculate_stable > 1 * 1000 / 100) {
            fi_calculate_stable = 0;
            elect = ControllerParserMain::con_telemetry[no].elect * 10; //1%1000
            if (elect >= g->charge_elect()) {
                if (elect - g->charge_elect() < 250 * 1000) {
                    fi_calculate((enum fee_number)no, _time, elect);
                    g->set_stop_time(get_fi_end_time((enum fee_number)no));
                    g->set_charge_time(g->stop_time() - g->start_time());
                }
            }
        }

        //data - 填充充电枪实时数据
        OiovCallback::ops_property_charge_data[no].output_voltage = ControllerParserMain::con_telemetry[no].charg_out_vol; //1%10
        OiovCallback::ops_property_charge_data[no].output_current = 4000 - ControllerParserMain::con_telemetry[no].charg_out_cur; //1%10
        OiovCallback::ops_property_charge_data[no].line_temp = 50;
        OiovCallback::ops_property_charge_data[no].soc = ControllerParserMain::con_telemetry[no].soc;
        OiovCallback::ops_property_charge_data[no].battery_max_temp = ControllerParserMain::con_telemetry[no].temp_max;
        OiovCallback::ops_property_charge_data[no].charging_time = get_fi_total_time((enum fee_number)no) / 60;
        OiovCallback::ops_property_charge_data[no].remaining_charging_time = ControllerParserMain::con_telemetry[no].surpl_charg_time;
        OiovCallback::ops_property_charge_data[no].charging_elect = get_fi_total_elect((enum fee_number)no);
        OiovCallback::ops_property_charge_data[no].loss_calculation_elect = OiovCallback::ops_property_charge_data[no].charging_elect;
        OiovCallback::ops_property_charge_data[no].charging_fee = get_fi_total_elec_fee((enum fee_number)no) + get_fi_total_service_fee((enum fee_number)no);
        OiovCallback::ops_property_charge_data[no].fault = 0x00;

        //data - 填充交易记录
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.year  = _tm->tm_year + 1900 - 2000;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.month = _tm->tm_mon + 1;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.mday  = _tm->tm_mday;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.wday  = _tm->tm_wday;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.hour  = _tm->tm_hour;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.min   = _tm->tm_min;
        OiovCallback::ops_event_bill[no].stop_time.cp56time2a_tm.msec  = _tm->tm_sec * 1000;
        OiovCallback::ops_event_bill[no].sharp_unit_fee = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP) * 10 + get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP) * 10;
        OiovCallback::ops_event_bill[no].sharp_total_elect = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP);
        OiovCallback::ops_event_bill[no].sharp_loss_calculation_elect = OiovCallback::ops_event_bill[no].sharp_total_elect;
        OiovCallback::ops_event_bill[no].sharp_total_fee = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP) + get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP);
        OiovCallback::ops_event_bill[no].peak_unit_fee = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK) * 10 + get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK) * 10;
        OiovCallback::ops_event_bill[no].peak_total_elect = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK);
        OiovCallback::ops_event_bill[no].peak_loss_calculation_elect = OiovCallback::ops_event_bill[no].peak_total_elect;
        OiovCallback::ops_event_bill[no].peak_total_fee = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK) + get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK);
        OiovCallback::ops_event_bill[no].flat_unit_fee = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT) * 10 + get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT) * 10;
        OiovCallback::ops_event_bill[no].flat_total_elect = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT);
        OiovCallback::ops_event_bill[no].flat_loss_calculation_elect = OiovCallback::ops_event_bill[no].flat_total_elect;
        OiovCallback::ops_event_bill[no].flat_total_fee = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT) + get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT);
        OiovCallback::ops_event_bill[no].valley_unit_fee = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY) * 10 + get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY) * 10;
        OiovCallback::ops_event_bill[no].valley_total_elect = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY);
        OiovCallback::ops_event_bill[no].valley_loss_calculation_elect = OiovCallback::ops_event_bill[no].valley_total_elect;
        OiovCallback::ops_event_bill[no].valley_total_fee = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY) + get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY);
        memset(OiovCallback::ops_event_bill[no].total_meter_stop, 0x00, sizeof(OiovCallback::ops_event_bill[no].total_meter_stop));
        OiovCallback::ops_event_bill[no].total_elect = get_fi_total_elect((enum fee_number)no);
        OiovCallback::ops_event_bill[no].total_loss_calculation_elect = OiovCallback::ops_event_bill[no].total_elect;
        OiovCallback::ops_event_bill[no].charging_fee = get_fi_total_elec_fee((enum fee_number)no) + get_fi_total_service_fee((enum fee_number)no);
        memcpy(&OiovCallback::ops_event_bill[no].vin, &ControllerParserMain::con_charg_start_result[no].vin, sizeof(ControllerParserMain::con_charg_start_result[no].vin));
        OiovCallback::ops_event_bill[no].transaction_date = OiovCallback::ops_event_bill[no].stop_time;

        //update order
        if (++order_stable > 10 * 1000 / 100) {
            order_stable = 0;
            vhash.clear();
            if (OiovCallback::OPS_TRANSACTION_TYPE_APP == OiovCallback::ops_event_bill[no].transaction_type) {
                str.clear();
                for (i = 0; i < sizeof(OiovCallback::ops_event_bill[no].stop_time.tm); ++i) {
                    str += QString("%1").arg(OiovCallback::ops_event_bill[no].stop_time.tm[i], 2, 16, QLatin1Char('0')).toUpper();
                }
                vhash["stop_time"] = str;
                vhash["stop_reason"] = OiovCallback::ops_event_bill[no].stop_reason;
                str.clear();
                for (i = 0; i < sizeof(OiovCallback::ops_event_bill[no].vin); ++i) {
                    str += QString("%1").arg(OiovCallback::ops_event_bill[no].vin[i], 2, 16, QLatin1Char('0'));
                }
                vhash["vin_code"] = str;
                vhash["sharp_elec_unit_fee"] = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP) * 10;
                vhash["sharp_service_unit_fee"] = get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP) * 10;
                vhash["sharp_total_elect"] = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP);
                vhash["sharp_loss_elect"] = OiovCallback::ops_event_bill[no].sharp_total_elect;
                vhash["sharp_elec_total_fee"] = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP);
                vhash["sharp_service_total_fee"] = get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_SHARP);
                vhash["peak_elec_unit_fee"] = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK) * 10;
                vhash["peak_service_unit_fee"] = get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK) * 10;
                vhash["peak_total_elect"] = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK);
                vhash["peak_loss_elect"] = OiovCallback::ops_event_bill[no].peak_total_elect;
                vhash["peak_elec_total_fee"] = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK);
                vhash["peak_service_total_fee"] = get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_PEAK);
                vhash["flat_elec_unit_fee"] = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT) * 10;
                vhash["flat_service_unit_fee"] = get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT) * 10;
                vhash["flat_total_elect"] = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT);
                vhash["flat_loss_elect"] = OiovCallback::ops_event_bill[no].flat_total_elect;
                vhash["flat_elec_total_fee"] = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT);
                vhash["flat_service_total_fee"] = get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_FLAT);
                vhash["valley_elec_unit_fee"] = get_fi_price_elec((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY) * 10;
                vhash["valley_service_unit_fee"] = get_fi_price_service((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY) * 10;
                vhash["valley_total_elect"] = get_fi_price_elect((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY);
                vhash["valley_loss_elect"] = OiovCallback::ops_event_bill[no].valley_total_elect;
                vhash["valley_elec_total_fee"] = get_fi_price_elec_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY);
                vhash["valley_service_total_fee"] = get_fi_price_service_fee((enum fee_number)no, FEE_STRATEGY_PRICE_TPYE_VALLEY);
                vhash["total_elect"] = get_fi_total_elect((enum fee_number)no);
                vhash["total_loss_elect"] = OiovCallback::ops_event_bill[no].total_elect;
                vhash["total_elec_cost"] = get_fi_total_elec_fee((enum fee_number)no);
                vhash["total_service_cost"] = get_fi_total_service_fee((enum fee_number)no);
                vhash["order_state"] = RecordMain::KOrderProcessing;
                str.clear();
                for (i = 0; i < sizeof(OiovCallback::ops_event_bill[no].serial_number); ++i) {
                    str += QString("%1").arg(OiovCallback::ops_event_bill[no].serial_number[i], 2, 16, QLatin1Char('0'));
                }
                RecordMain::m_baseRecord.UpdateRecord(vhash, "trade_no", str);
            }
        }

        if (OiovReqMain::AppStopChargeService(no)) {
            OiovReqMain::ClearAppStopChargeService(no); //清除标志位

            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "app stop charging";

            g->set_stop_timeout(STOP_TIMEOUT * 1000 / 100);

            ChangeState(g, StopingStatus::instance()); //切换到充电停止中

#if defined(CHARGINGSTATE_DEBUG)
            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging -> stoping";
#endif

            //stop charging - 告诉控制器可以结束充电了
            memset(&(ControllerParserMain::con_frame_info[CON_PDUFORMAT_FEEDBACK_STOP_CHARG]), 0x00, sizeof(con_frame_info_t));
            ControllerSendMain::con_stop_charg[no].gnu_no = no + CONGUNNOA;
            ControllerSendMain::con_stop_charg[no].result_code = 1;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].gunno = no + CONGUNNOA;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].cycle = 250;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].count = 0;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].timeout = 5000;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].time = controller_time();
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].pduformat = CON_PDUFORMAT_STOP_CHARG;

            //data - 填充交易记录
            OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_STOP_CHARGING_CODE_40;
        } else if (CardMain::StopChargeService(no)) {
            CardMain::ClearStopChargeService(no); //清除标志位

            char *card_num = g->card_number();
            QByteArray card_number = CardMain::card_number();
            for (int i = 0; i < 16 && i < card_number.size(); ++i) {
                if (*(card_num + i) != card_number[i]) {
                    return;
                }
            }

            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "card stop charging";

            g->set_stop_timeout(STOP_TIMEOUT * 1000 / 100);

            ChangeState(g, StopingStatus::instance()); //切换到充电停止中

#if defined(CHARGINGSTATE_DEBUG)
            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging -> stoping";
#endif

            //stop charging - 告诉控制器可以结束充电了
            ControllerSendMain::con_stop_charg[no].gnu_no = no + CONGUNNOA;
            ControllerSendMain::con_stop_charg[no].result_code = 1;
            memset(&(ControllerParserMain::con_frame_info[CON_PDUFORMAT_FEEDBACK_STOP_CHARG]), 0x00, sizeof(con_frame_info_t));
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].gunno = no + CONGUNNOA;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].cycle = 250;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].count = 0;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].timeout = 5000;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].time = controller_time();
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].pduformat = CON_PDUFORMAT_STOP_CHARG;

            //data - 填充交易记录
            OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_STOP_CHARGING_CODE_45;
        } else if (HciMain::StopChargeService(no)) {
            HciMain::ClearStopChargeService(no); //清除标志位

            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "hci stop charging";

            g->set_stop_timeout(STOP_TIMEOUT * 1000 / 100);

            ChangeState(g, StopingStatus::instance()); //切换到充电停止中

#if defined(CHARGINGSTATE_DEBUG)
            qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging -> stoping";
#endif

            //stop charging - 告诉控制器可以结束充电了
            ControllerSendMain::con_stop_charg[no].gnu_no = no + CONGUNNOA;
            ControllerSendMain::con_stop_charg[no].result_code = 1;
            memset(&(ControllerParserMain::con_frame_info[CON_PDUFORMAT_FEEDBACK_STOP_CHARG]), 0x00, sizeof(con_frame_info_t));
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].gunno = no + CONGUNNOA;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].cycle = 250;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].count = 0;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].timeout = 5000;
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].time = controller_time();
            ControllerSendMain::con_frame_info[CON_PDUFORMAT_STOP_CHARG].pduformat = CON_PDUFORMAT_STOP_CHARG;

            //data - 填充交易记录
            OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_STOP_CHARGING_CODE_45;
        } else {
            //...
        }
        break;
    case FULL_STATE:
        break;
    case WARRING_STATE:
        break;
    case FAULT_STATE:
        ChangeState(g, FinishStatus::instance()); //切换到充电完成未拔枪

#if defined(CHARGINGSTATE_DEBUG)
        qDebug() << "[CHARGE]->" << (no ? "No.b" : "No.a") << "charging -> finish";
#endif

        //充电结束，不要上报充电中的属性数据了
        OiovReqMain::ClearChargingProperty(no);

        //设备状态 -> 充电结束未拔枪
        OiovCallback::ops_property_charge_data[no].status = OiovCallback::OPS_CHARGINGPILE_STATE_IDLE;
        //向平台发送设备状态事件
        OiovReqMain::SetDeviceStatusEvent(no);

        //data - 填充交易记录
        switch (ControllerParserMain::con_charg_stop_result[no].result_code) {
        case 0x02:
            switch (ControllerParserMain::con_charg_stop_result[no].fault_code_one) {
            case 0x01:
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_72; //急停故障
                break;
            case 0x04:
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_71; //绝缘模块故障
                break;
            default:
                break;
            }
            break;
        case 0x05:
            if (0x01 == ControllerParserMain::con_charg_stop_result[no].con_bms_fault_code.bms_fault_code_out_link_overtemp) {
                OiovCallback::ops_event_bill[no].stop_reason = OiovCallback::DEV_ABORT_CHARGING_CODE_74; //输出连接器过温故障
            }
            break;
        default:
            break;
        }
        //上报交易记录
        if (OiovCallback::OPS_TRANSACTION_TYPE_APP == OiovCallback::ops_event_bill[no].transaction_type || OiovCallback::OPS_TRANSACTION_TYPE_ONCARD == OiovCallback::ops_event_bill[no].transaction_type) {
            OiovReqMain::SetStopChargeEvent(no);
        }
        break;
    default:
        break;
    }
}
